/*
 * atcmd.c
 *	功能：实现读出设备序列号和写入
 *  Created on: 2021年8月1日
 *  Author: LENOVO
 */
#include "atcmd.h"
#include "string.h"
#include "stdio.h"
#include "usart.h"
#include "stdlib.h"
#define clear_buf() 				do{memset(buf_usart1,0,sizeof(buf_usart1));counter_usart1=0;}while(0)

#define AT_BEGIN_ADDRESS 			0x0801F800
#define AT_SN_ADDRESS 				0x0801F800
#define AT_WLAN_ADDRESS 			0x0801F820
#define AT_MQTT_ADDRESS 			0x0801F860
#define AT_TIMEOUT_ADDRESS 			0x0801F950
#define AT_CALENDAR_ADDRESS 		0x0801F958
#define AT_FLAG_ADDRESS 			0x0801F974

//串口数据
extern uint8_t 						buf_usart1[256];
extern uint8_t 						counter_usart1;
_Bool 								atmod_state;
uint8_t 							MAPS_LENTH;
//config
config at_config;
//函数指针定义
typedef void (*func)(uint8_t,char *);
enum
{
	ATCMD_TYPE_HELP = 0,//提示
	ATCMD_TYPE_GET_VALUE,//带值 得到取值范围 设置值
	ATCMD_TYPE_SET_VALUE,//带值 设置值
	ATCMD_TYPE_EXECUTE,//执行 单命令
};
/*
 * 结构体
 */
typedef struct
{
	char ins_query[20];
	func ins_ptr;
}map_func;
typedef struct
{
	char tip_query[50];
	char tip_message[50];
}maps_func_tips;
typedef struct
{
	char parameter_query[50];
	char parameter_message[50];
}maps_func_Parameter;
//函数声明
void AT_get_flash_data(uint8_t lenth,char *value);		//获得数据
void AT_serial(uint8_t lenth,char *value);				//序列号
void AT_wlan(uint8_t lenth,char *value);				//wifi配置
void AT_timeout(uint8_t lenth,char *value);			//上传时间
void AT_mqtt(uint8_t lenth,char *value);				//mqtt设置
void AT_calendar(uint8_t lenth,char *value);			//产品生产日期
void AT_done(uint8_t lenth,char *value);			//写入
void AT_clear(uint8_t lenth,char *value);			//清除所有的flash数据
void AT_get_current_cofig(uint8_t lenth,char *value);//得到结构体现在的值
/*
 * 结构体数组
 */
//查找指令并执行
map_func maps[]=
{
	{"AT+SN",		AT_serial},
	{"AT+WLAN",		AT_wlan},
	{"AT+TIMEOUT",	AT_timeout},
	{"AT+CMD",		AT_done},
	{"AT+MQTT",		AT_mqtt},
	{"AT+FDATA",	AT_get_flash_data},
	{"AT+CAL",		AT_calendar},
	{"AT+CLEAR",	AT_clear},
	{"AT+CONFIG",	AT_get_current_cofig},
};
//查找指令提示信息
maps_func_tips maps_message_tips[]=
{
	{"AT+SN",		"Set product serial number"},
	{"AT+WLAN",		"Set wireless connection information"},
	{"AT+TIMEOUT",	"Set reporting interval"},
	{"AT+CMD",		"0:EXIT ATMODE"},
	{"AT+MQTT",		"Set mqtt parameters"},
	{"AT+FDATA",	"GET FLASH DATA"},
	{"AT+CAL",		"SET TIME"},
	{"AT+CLEAR",	"CLEAR THE FLASH"},
	{"AT+CONFIG",	"GET STRUCT CONFIG"},
};
//查找指令返回可设置参数
maps_func_Parameter maps_message_prameter[]=
{
	{"AT+SN",		"AT+SN=BearKE-0001--BearKE-9999"},
	{"AT+WLAN",		"AT+WLAN=SSID,PASSWD"},
	{"AT+TIMEOUT",	"AT+TIMEOUT=60-3600"},
	{"AT+CMD",		"AT+CMD=0:EXIT ATMODE"},
	{"AT+MQTT",		"AT+MQTT=HOSTNAME,PORT,CLIENTID,UID,PWD,TOPIC"},
	{"AT+FDATA",	"NULL"},
	{"AT+CAL",		"NULL"},
	{"AT+CLEAR",	"NULL"},
	{"AT+CONFIG",	"NULL"},
};
/*
 * 结构体功能函数
 */
void init_at_config()//从flash里面读取数据初始化 只有在判断flash已经写入才调用 否则不调用
{
	char 					read_data[241]={'\0'};
	//sn
	if(!flash_read((uint32_t)AT_SN_ADDRESS,sizeof(at_config.serial),read_data))
		memcpy(at_config.serial,(char *)read_data,sizeof(at_config.serial));
	memset(read_data,0,sizeof(read_data));

	//wlan
	if(!flash_read((uint32_t)AT_WLAN_ADDRESS,sizeof(at_config.wlan),read_data))
		memcpy(at_config.wlan,(char *)read_data,sizeof(at_config.wlan));
	memset(read_data,0,sizeof(read_data));

	//MQTT
	if(!flash_read((uint32_t)AT_MQTT_ADDRESS,sizeof(at_config.mqtt),read_data))
		memcpy(at_config.mqtt,(char *)read_data,sizeof(at_config.mqtt));
	memset(read_data,0,sizeof(read_data));

	//TIMEOUT
	if(!flash_read((uint32_t)AT_TIMEOUT_ADDRESS,sizeof(at_config.timeout),read_data))
		memcpy(at_config.timeout,(char *)read_data,sizeof(at_config.timeout));
	memset(read_data,0,sizeof(read_data));

	//calendar
	if(!flash_read((uint32_t)AT_CALENDAR_ADDRESS,sizeof(at_config.calendar),read_data))
		memcpy(at_config.calendar,(char *)read_data,sizeof(at_config.calendar));
	memset(read_data,0,sizeof(read_data));
}
void AT_get_flash_data(uint8_t lenth,char *value)
{
	char 					read_data[241]={'\0'};
	//SN
	if(!flash_read((uint32_t)AT_SN_ADDRESS,sizeof(at_config.serial),read_data))
	{
		printf("SN:%s\r\n",read_data);
	}
	else
		printf("SN error\r\n");
	memset(read_data,0,sizeof(read_data));

	//WALN
	if(!flash_read((uint32_t)AT_WLAN_ADDRESS,sizeof(at_config.wlan),read_data))
	{
		printf("WLAN:%s\r\n",read_data);
	}
	else
		printf("WLAN error\r\n");
	memset(read_data,0,sizeof(read_data));

	//MQTT
	if(!flash_read((uint32_t)AT_MQTT_ADDRESS,sizeof(at_config.mqtt),read_data))
	{
		printf("MQTT:%s\r\n",read_data);
	}
	else
		printf("MQTT error\r\n");
	memset(read_data,0,sizeof(read_data));

	//TIMEOUT
	if(!flash_read((uint32_t)AT_TIMEOUT_ADDRESS,sizeof(at_config.timeout),read_data))
	{
		printf("TIMEOUT:%s\r\n",read_data);
	}
	else
		printf("TIMEOUT error\r\n");
	memset(read_data,0,sizeof(read_data));

	//日期
	if(!flash_read((uint32_t)AT_CALENDAR_ADDRESS,sizeof(at_config.calendar),read_data))
	{
		printf("CALENDAR:%s\r\n",read_data);
	}
	else
		printf("CALENDAR error\r\n");
	memset(read_data,0,sizeof(read_data));
}

void AT_serial(uint8_t lenth,char *value)//输入序列号
{
	if(lenth>=sizeof(at_config.serial))
	{
		printf("SN:Warning data too long\r\n");
		return;
	}
	memset(at_config.serial,'\0',sizeof(at_config.serial));
	memcpy(at_config.serial,value,strlen(value)+1);

	//打印成功
	printf("SN:ok\r\n");
}
void AT_wlan(uint8_t lenth,char *value)//wifi配置
{
	if(lenth>=sizeof(at_config.wlan))
	{
		printf("WLAN:Warning data too long\r\n");
		return;
	}
	memset(at_config.wlan,'\0',sizeof(at_config.wlan));
	memcpy(at_config.wlan,value,strlen(value)+1);

	printf("WLAN;ok\r\n");
}
void AT_timeout(uint8_t lenth,char *value)//上传时间
{
	if(lenth>=sizeof(at_config.timeout))
	{
		printf("TIMEOUT:Warning data too long\r\n");
		return;
	}
	memset(at_config.timeout,'\0',sizeof(at_config.timeout));
	memcpy(at_config.timeout,value,strlen(value)+1);

	printf("TIMEOUT:ok\r\n");
}
void AT_mqtt(uint8_t lenth,char *value)//mqtt设置
{
	if(lenth>=sizeof(at_config.mqtt))
	{
		printf("MQTT:Warning data too long\r\n");
		return;
	}
	memset(at_config.mqtt,'\0',sizeof(at_config.mqtt));
	memcpy(at_config.mqtt,value,strlen(value)+1);

	printf("MQTT:ok\r\n");
}
void AT_calendar(uint8_t lenth,char *value)
{
	if(lenth>=sizeof(at_config.calendar))
	{
		printf("CAL:Warning data too long\r\n");
		return;
	}
	memset(at_config.calendar,'\0',sizeof(at_config.calendar));
	memcpy(at_config.calendar,value,strlen(value)+1);

	printf("CAL:ok\r\n");
}
//退出AT模式 保存数据到flash
void AT_done(uint8_t lenth,char *value)
{
	if(strstr(value,"0"))
	{
		if((!strlen(at_config.serial)) &&(!strlen(at_config.wlan)) &&(!strlen((char *)at_config.timeout)) &&(!strlen(at_config.mqtt)) &&(!strlen(at_config.calendar)))
		{
			memcpy(at_config.flag,"no",2);
		}
		else
		{
			memcpy(at_config.flag,"ok",2);
		}

		if(!flash_write((uint32_t)AT_BEGIN_ADDRESS,sizeof(at_config),(char *)&at_config))
			printf("Atmod write ok\r\n");
		else
			printf("Atmod write error\r\n");
		//灭灯提示结束AT模式
		HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
		atmod_state=0;
	}
}
void AT_clear(uint8_t lenth,char *value)//清除所有的flash数据
{
	flash_erase(62,63);
	//清除结构体数组
	memset(at_config.calendar,'\0',sizeof(at_config.calendar));
	memset(at_config.timeout,'\0',sizeof(at_config.timeout));
	memset(at_config.serial,'\0',sizeof(at_config.serial));
	memset(at_config.wlan,'\0',sizeof(at_config.wlan));
	memset(at_config.mqtt,'\0',sizeof(at_config.mqtt));
	memset(at_config.flag,'\0',sizeof(at_config.flag));
	printf("ok!\r\n");
}
void AT_get_current_cofig(uint8_t lenth,char *value)
{
//SN
	printf("SN:%s\r\n",at_config.serial);
//WALN
	printf("WLAN:%s\r\n",at_config.wlan);
//TIMEOUT
	printf("TIMEOUT:%s\r\n",at_config.timeout);
//mqtt
	printf("MQTT:%s\r\n",at_config.mqtt);
//日期
	printf("CALENDAR:%s\r\n",at_config.calendar);
}
/*
* 执行函数
* 函数功能：查找指令 执行动作
*/
void process_handle(char *head_data,uint8_t len,char *value,uint8_t at_type)//匹配指令执行函数
{
	uint8_t 					i=0;

	for(i=0;i<MAPS_LENTH;i++)
	{
		if(!strncmp(head_data,maps[i].ins_query,strlen(maps[i].ins_query)))
		{
			//如果找到了 就执行
			switch(at_type)
				{
				case 	ATCMD_TYPE_HELP:
					printf("Tips:%s\r\n",maps_message_tips[i].tip_message);
					break;
				case	ATCMD_TYPE_GET_VALUE:
					printf("Parameter:%s\r\n",maps_message_prameter[i].parameter_message);
					break;
				case	ATCMD_TYPE_SET_VALUE:
					maps[i].ins_ptr(len,value);
					break;
				case	ATCMD_TYPE_EXECUTE:
					maps[i].ins_ptr(len,value);
					break;
				default:break;
				}

			break;
		}
	}
}
uint8_t get_at_type(char *at_start,uint8_t *len,char **value,char **head_data)
{
	char 						*point;

	if((point=strchr(at_start,'=')))//AT+SN=
	{
		*point='\0';
		*head_data=at_start;

		if(*(point+1)=='?')//AT+SN=?
		{
			*value="null";
			*len=0;
			return ATCMD_TYPE_GET_VALUE;
		}

		else////AT+SN=value
		{
			*value=point+1;
			*len=strlen(*value);
			return ATCMD_TYPE_SET_VALUE;
		}
	}

	else if((point=strchr(at_start,'?')))//AT+SN?
	{
		*point='\0';
		*head_data=at_start;
		*value="null";
		*len=0;
		return ATCMD_TYPE_HELP;
	}

	else//AT
	{
		*head_data=at_start;
		*value="null";
		*len=0;
		return ATCMD_TYPE_EXECUTE;
	}
}
/*
 *
* 执行函数
* 函数功能：AT模式 一直处理AT数据
*/
void process_run()
{
	char 							*at_start;
	char 							*at_end;
	char 							*value;
	char							*head_data;
	uint8_t 						lenth;
	uint8_t 						at_type;


	//亮灯表示进入AT模式
	MAPS_LENTH=sizeof(maps_message_tips)/sizeof(maps_func_tips);//求指令的条数

	atmod_state=1;
	HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
	printf("Enter atmode\r\n");

	clear_buf();
	while(1)//循环配置AT
	{
		if(get_buf_end_flag())//如果接收完成
		{
			if(strlen((char *)buf_usart1)>250)//如果指令太长 则不处理
			{
				printf("Atmode instructions is too long ,please input it again\r\n");
				continue;
			}
			if( (at_start=strstr((char*)buf_usart1,"AT+") )  && ( (at_end=strchr((char*)buf_usart1,'\r')) || (at_end=strchr((char*)buf_usart1,'\n')) ) )
			{
				*at_end='\0';//加结束符号 方便处理
				if(strlen((char *)buf_usart1)>strlen(at_start))//如果AT+XXX前面包含了其他字符 则提示错误字符 要求重新输入
				{
					printf("Wrong instruction,please input it again\r\n");
					continue;
				}
				//判断指令类型
				at_type=get_at_type(at_start,&lenth,&value,&head_data);//取出头部和有效值部分
				process_handle(head_data,lenth,value,at_type);
			}
			if(!atmod_state)
				return ;
			clear_buf();
		}
	}
}
/*
 * 执行函数
 * 函数功能：判断进入AT模式没有 十秒钟
 */
void process_master()//判断十秒内有没有指令进入，并且是不是正确的AT+CMD=1,如果不是，则计时继续，然后时间到则跳出
{
	char 			read_data[3]={'\0'};
	uint32_t 		ticks=10000;
	uint32_t 		told;
	uint32_t		tnow;

	told=HAL_GetTick(); //刚进入时的计数器值
	//判断有没有写入过配置 没有的话就直接进入 否则判断指令进入
	if(!flash_read((uint32_t)AT_FLAG_ADDRESS,2,read_data))
	{
		if(!strcmp("ok",(char *)read_data))
		{
			init_at_config();
			printf("Flash had been written\r\n");
		}
		else
		{

			printf("Flash had not been written\r\n");
			process_run();
			printf("Atmode set scuessful\r\n");
			return;
		}
	}
	//判断指令进入
	printf("Determine whether to enter?\r\n");
	clear_buf();
	while(1)//十秒钟判断有没有得到AT+CMD=1
	{
		//下面是十秒钟时间判断，如果十秒内没有收到指令，就退出
		tnow=HAL_GetTick();
		if(tnow!=told)
		{
			if((tnow+0xFFFFFFFF-told)%0xFFFFFFFF>ticks)
			{
				printf("Wait atmode exit\r\n");
				break;			//时间超过/等于要延迟的时间,则退出.
			}
		}

		if(get_buf_end_flag())//如果接收完成
		{
			//接收完成 判断数据
			//下面是字符判断
			if(strstr((char *)buf_usart1,"AT+CMD=1"))
			{
				//进入at 模式循环 等待 指令退出
				process_run();
				printf("Atmode set scuessful\r\n");
			}
			clear_buf();
		}

	}
}
void get_sn(char *sn_data)
{
	char 					read_data[241]={'\0'};
	char					*read_start;
	char					*read_end;
	if(!flash_read((uint32_t)AT_SN_ADDRESS,sizeof(at_config.serial),read_data))
	{
		printf("Sn read ok\r\n");
	}
	else
		printf("SN read error\r\n");

	read_start=(strchr(read_data,'\"')+1);
	read_end=strchr(read_start,'\"');
	*read_end='\0';
	memcpy(sn_data,read_start,strlen(read_start)+1);
}
void get_mqtt(char *hostname,int *port,char *clientid,char *uid,char *pwd,char *topic)
{
	char 					read_data[241]={'\0'};
	char 					*l_hostname;
	char 					*l_port;
	char 					*l_clientid;
	char 					*l_uid;
	char 					*l_pwd;
	char 					*l_topic;
	char					*read_start;
	char					*read_end;

	char 					swap_port[10];
	if(!flash_read((uint32_t)AT_MQTT_ADDRESS,sizeof(at_config.mqtt),read_data))
	{
		printf("Mqtt read ok\r\n");
	}
	else
		printf("Mqtt read error\r\n");
	//把头尾的"去掉
	read_start=(strchr(read_data,'\"')+1);
	l_hostname=strtok(read_start,"\",");
	l_port= strtok(NULL, ",\"");
	l_clientid=strtok(NULL,"\",\"");
	l_uid=strtok(NULL,"\",\"");
	l_pwd= strtok(NULL, "\",\"");
	l_topic= strtok(NULL, "\",\"");

	read_end=strchr(l_topic,'\"');
	*read_end='\0';
	memcpy(hostname,l_hostname,strlen(l_hostname)+1);
	memcpy(swap_port,l_port,strlen(l_port)+1);
	*port=atoi(swap_port);
	memcpy(clientid,l_clientid,strlen(l_clientid)+1);
	memcpy(uid,l_uid,strlen(l_uid)+1);
	memcpy(pwd,l_pwd,strlen(l_pwd)+1);
	memcpy(topic,l_topic,strlen(l_topic)+1);
}
void get_wlan(char * id,char * pwd)
{
	char 					read_data[241]={'\0'};
	char                   *l_id;
	char                   *l_pwd;

	char					*read_start;
	char					*read_end;
	if(!flash_read((uint32_t)AT_WLAN_ADDRESS,sizeof(at_config.wlan),read_data))
	{
		printf("Wlan read ok\r\n");
	}
	else
		printf("Wlan read error\r\n");

	read_start=(strchr(read_data,'\"')+1);

	l_id=strtok(read_start,"\",\"");
	l_pwd= strtok(NULL, "\",\"");

	read_end=strchr(l_pwd,'\"');
	*read_end='\0';

	memcpy(id,l_id,strlen(l_id)+1);
	memcpy(pwd,l_pwd,strlen(l_pwd)+1);
}
void get_timeout(int * timeout)
{
	char 					read_data[241]={'\0'};

	if(!flash_read((uint32_t)AT_TIMEOUT_ADDRESS,sizeof(at_config.timeout),read_data))
	{
		printf("Timeout read ok\r\n");
	}
	else
		printf("Timeout read error\r\n");
	*timeout=atoi(read_data);
}
void get_calendar(char* calendar_data)
{
	char 					read_data[200]={'\0'};
	char					*read_start;
	char					*read_end;

	if(!flash_read((uint32_t)AT_CALENDAR_ADDRESS,sizeof(at_config.calendar),read_data))
	{
		printf("Calendar read ok\r\n");
	}
	else
		printf("Calendar read error\r\n");
	read_start=(strchr(read_data,'\"')+1);
	read_end=strchr(read_start,'\"');
	*read_end='\0';
	memcpy(calendar_data,read_start,strlen(read_start)+1);
}
